package is.server.model.xtool;

import is.common.exception.DroppingNonEmptyDepartmentException;
import is.common.exception.RowNotFoundException;
import is.common.exception.RowsAreaIncorrectException;
import is.common.exception.UniqueCheckFailedException;
import is.common.util.Compressor;
import org.w3c.dom.Document;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;

import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.validation.SchemaFactory;
import java.io.*;

/**
 * XML tools front-end class. <p/>
 * Holds main XML tree document. <p/>
 *
 * @author aspr0
 *         Date: 16.04.12
 *         Time: 18:56
 */
public class Xtool
{
    private String dbFileName;
    private InputStream dbFileInputStream;
    private OutputStream dbFileOutputStream;
    /**
     * Main XML tree document
     */
    private Document dbDoc;
    private SectionArbiter sectionArbiter;

    /**
     * Parser
     */
    private DocumentBuilder documentBuilder;

    public Document getDbDoc()
    {
        return dbDoc;
    }

    public Xtool(String schemaFileName) throws SAXException, ParserConfigurationException
    {
        File schemaFile = new File(schemaFileName);

        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
        documentBuilderFactory
                .setSchema(SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI).newSchema(schemaFile));
        /* no whitespace nodes anymore!!! */
        documentBuilderFactory.setIgnoringElementContentWhitespace(true);

        documentBuilder = documentBuilderFactory.newDocumentBuilder();
        ErrorHandler errorHandler = new ParseErrorHandler();
        documentBuilder.setErrorHandler(errorHandler);

    }

    /**
     * @throws IOException  if file couldn't be read
     * @throws SAXException if parse errors occur
     */
    public void parseFile() throws IOException, SAXException
    {
        openDbFileInputStream();
        dbDoc = documentBuilder.parse(dbFileInputStream);
        dbFileInputStream.close();

        sectionArbiter = new SectionArbiter(dbDoc);
        sectionArbiter.parseDoc();
    }

    public int concat(Document dbDocAlien)
    {
        return sectionArbiter.concat(dbDocAlien);
    }

    public void initFile()
    {
        dbDoc = documentBuilder.newDocument();
        sectionArbiter = new SectionArbiter(dbDoc);
        sectionArbiter.initDoc();
        sectionArbiter.parseDoc();
    }

    /**
     * @throws IOException if file couldn't be read
     * @throws javax.xml.transform.TransformerException
     *                     error transforming xml to file
     */
    public void saveFile() throws TransformerException, IOException
    {
        openDbFileOutputStream();
        TransformerFactory.newInstance().newTransformer()
                .transform(new DOMSource(dbDoc), new StreamResult(dbFileOutputStream));
        dbFileOutputStream.close();
    }


    public String[] getHeader(Integer sectionNum)
    {
        return sectionArbiter.selectAdapter(sectionNum).getHeader();
    }


    public String[][] getRows(Integer sectionNum, Integer rowNumStart, Integer howMany)
            throws RowsAreaIncorrectException, RowNotFoundException
    {
        return sectionArbiter.selectAdapter(sectionNum).getRows(rowNumStart, howMany);
    }


    public void addRow(Integer sectionNum, String[] row) throws RowNotFoundException, UniqueCheckFailedException
    {
        sectionArbiter.selectAdapter(sectionNum).addRow(row);
    }


    public void editRow(Integer sectionNum, String[] row) throws UniqueCheckFailedException, RowNotFoundException
    {
        sectionArbiter.selectAdapter(sectionNum).editRow(row);
    }


    public String dropRows(Integer sectionNum, String[] rowNums) throws DroppingNonEmptyDepartmentException
    {
        return sectionArbiter.selectAdapter(sectionNum).dropRows(rowNums);
    }

    public String[][] findRows(Integer sectionNum, String[] masks) throws RowNotFoundException
    {
        return sectionArbiter.selectAdapter(sectionNum).findRows(masks);
    }

    public void setFileName(String dbFileName)
    {
        this.dbFileName = dbFileName;
    }


    private void openDbFileInputStream() throws IOException
    {
        dbFileInputStream = Compressor.uncompress(new FileInputStream(dbFileName));
    }

    private void openDbFileOutputStream() throws IOException
    {
        dbFileOutputStream = Compressor.compress(new FileOutputStream(dbFileName));
    }
}
